<script setup>
import { computed } from 'vue';
import FileIcon from './FileIcon.vue';
import { useI18n } from 'vue-i18n';

const { t } = useI18n();

// Props
const props = defineProps({
  item: { type: Object, required: true }, // { node, depth, displayLabel }
  index: { type: Number, required: true },
  indent: { type: Number, default: 12 },
  rowHeight: { type: Number, default: 22 },
  isExpanded: { type: Function, required: true },
  isSelected: { type: Function, required: true },
  isNodeSelected: { type: Function, required: true },
  selectedId: { type: String, default: null },
  editingNodeId: { type: String, default: null },
  editingMode: { type: String, default: null },
  editingLabel: { type: String, default: '' },
  filterText: { type: String, default: '' },
  compressSeparator: { type: String, default: '/' },
  animateChanges: { type: Boolean, default: false },
  draggable: { type: Boolean, default: true },
  t: { type: Function, default: null },
});

// Emits
const emit = defineEmits([
  'click',
  'dblclick', 
  'contextmenu',
  'toggle',
  'load-children',
  'dragstart',
  'dragover',
  'dragleave',
  'drop',
  'dragend',
  'editing-input',
  'commit-inline',
  'cancel-inline',
  'update:editing-label'
]);

// Computed
const isDirectory = computed(() => {
  const node = props.item.node;
  return node && (node.isDir === true || node.is_dir === true || node.isFolder === true);
});

const isEditing = computed(() => {
  return String(props.item.node.id) === String(props.editingNodeId);
});

// Methods
function splitForHighlight(text, query) {
  const q = String(query || '').toLowerCase();
  const s = String(text || '');
  if (!q) return [{ text: s, hit: false }];
  const lower = s.toLowerCase();
  const parts = [];
  let i = 0;
  while (i < s.length) {
    const idx = lower.indexOf(q, i);
    if (idx === -1) { parts.push({ text: s.slice(i), hit: false }); break; }
    if (idx > i) parts.push({ text: s.slice(i, idx), hit: false });
    parts.push({ text: s.slice(idx, idx + q.length), hit: true });
    i = idx + q.length;
  }
  return parts;
}

function setEditingInput(el) {
  if (el) {
    emit('editing-input', el);
  }
}

async function onToggleClick() {
  try {
    // 先发送 load-children 事件并等待完成
    await emit('load-children', { node: props.item.node });
    // 然后才发送 toggle 事件
    emit('toggle', { node: props.item.node });
  } catch (error) {
    console.warn('Failed to load children before toggle:', error);
    // 即使加载失败，也允许切换展开状态
    emit('toggle', { node: props.item.node });
  }
}

function onRowClick(e) {
  emit('click', { node: props.item.node, event: e, index: props.index });
}

function onRowDblClick(e) {
  emit('dblclick', { node: props.item.node, event: e, index: props.index });
}

function onRowContextMenu(e) {
  emit('contextmenu', { node: props.item.node, event: e, index: props.index });
}

function onRowDragStart(e) {
  emit('dragstart', { node: props.item.node, event: e, index: props.index });
}

function onRowDragOver(e) {
  emit('dragover', { node: props.item.node, event: e, index: props.index });
}

function onRowDragLeave(e) {
  emit('dragleave', { node: props.item.node, event: e, index: props.index });
}

function onRowDrop(e) {
  emit('drop', { node: props.item.node, event: e, index: props.index });
}

function onRowDragEnd(e) {
  emit('dragend', { node: props.item.node, event: e, index: props.index });
}

function onCommitInline() {
  emit('commit-inline');
}

function onCancelInline() {
  emit('cancel-inline');
}
</script>

<template>
  <div
    class="flex items-center gap-1 rounded px-2 py-0.5 hover:bg-slate-200/40 dark:hover:bg-white/10 cursor-pointer min-w-0 select-none border-l-2 border-transparent transition-colors duration-150"
    :class="[
      (selectedId === item.node.id || isNodeSelected(item.node.id)) 
        ? 'bg-accent/15 dark:bg-accent/25 border-accent dark:border-accent/80' 
        : '', 
      animateChanges ? 'tv-anim' : ''
    ]"
    :style="{ paddingLeft: (item.depth * indent) + 'px' }"
    role="treeitem"
    :aria-level="item.depth + 1"
    :aria-expanded="isDirectory ? String(isExpanded(item.node.id)) : undefined"
    @click.stop="onRowClick"
    @dblclick.stop="onRowDblClick"
    @contextmenu.prevent.stop="onRowContextMenu"
    :draggable="draggable"
    @dragstart="onRowDragStart"
    @dragover="onRowDragOver"
    @dragleave="onRowDragLeave"
    @drop="onRowDrop"
    @dragend="onRowDragEnd"
  >
    <!-- 展开/折叠按钮 -->
    <template v-if="isDirectory">
      <button
        class="inline-flex h-4 w-4 items-center justify-center text-slate-500 dark:text-neutral-500"
        :aria-label="isExpanded(item.node.id) ? (t ? (t('explorer.collapse')||'Collapse') : 'Collapse') : (t ? (t('explorer.expand')||'Expand') : 'Expand')"
        :aria-expanded="isExpanded(item.node.id)"
        @click.stop="onToggleClick"
      >
        <svg 
          viewBox="0 0 24 24" 
          fill="none" 
          stroke="currentColor" 
          stroke-width="1.8" 
          stroke-linecap="round" 
          stroke-linejoin="round"
          :class="['h-3 w-3 transition-transform transform', isExpanded(item.node.id) ? 'rotate-90' : 'rotate-0']"
        >
          <path d="M9 6l6 6-6 6" />
        </svg>
      </button>
    </template>
    <span v-else class="inline-flex h-4 w-4"></span>

    <!-- 前缀插槽 -->
    <slot name="prefix" :node="item.node" :depth="item.depth"></slot>

    <!-- 文件图标 -->
    <span v-if="!isDirectory" class="inline-flex items-center justify-center ml-1 mr-1">
      <FileIcon :name="String(item.node.label || item.node.id || '')" :size="16" :isDir="false" />
    </span>

    <!-- 节点标签或编辑输入框 -->
    <span v-if="!isEditing" class="truncate" :title="item.displayLabel">
      <!-- 压缩路径显示 -->
      <template v-if="(item.displayLabel || '').includes(compressSeparator)">
        <template v-for="(seg, i) in (item.displayLabel || '').split(compressSeparator)" :key="i">
          <span :class="i < ((item.displayLabel || '').split(compressSeparator).length - 1) ? 'text-slate-500 dark:text-neutral-400' : ''">
            <template v-for="part in splitForHighlight(seg, filterText)" :key="part.text + String(part.hit)">
              <span :class="part.hit ? 'bg-yellow-300/30 dark:bg-yellow-400/40 text-gray-900 dark:text-yellow-100 font-medium' : ''">{{ part.text }}</span>
            </template>
          </span>
          <span v-if="i < ((item.displayLabel || '').split(compressSeparator).length - 1)" class="mx-0.5 text-slate-400">{{ compressSeparator }}</span>
        </template>
      </template>
      <!-- 普通标签显示 -->
      <template v-else>
        <template v-for="part in splitForHighlight(item.displayLabel, filterText)" :key="part.text + String(part.hit)">
          <span :class="part.hit ? 'bg-yellow-300/30 dark:bg-yellow-400/40 text-gray-900 dark:text-yellow-100 font-medium' : ''">{{ part.text }}</span>
        </template>
      </template>
    </span>
    
    <!-- 编辑输入框 -->
    <input 
      v-else
      class="px-1 py-0 text-[12px] leading-[22px] h-[22px] rounded outline-none border-0 focus:ring-1 focus:ring-blue-500/40 bg-white dark:bg-neutral-800 w-[220px] shadow-inner"
      :value="editingLabel"
      @input="$emit('update:editingLabel', $event.target.value)"
      :placeholder="editingMode==='new-folder' ? (t ? (t('explorer.new_folder_placeholder')||'New Folder') : 'New Folder') : (editingMode==='new-file' ? (t ? (t('explorer.new_file_placeholder')||'New File') : 'New File') : (t ? (t('explorer.rename_placeholder')||'Rename') : 'Rename'))"
      @keydown.enter.stop.prevent="onCommitInline"
      @keydown.esc.stop.prevent="onCancelInline"
      @blur="onCommitInline"
      :ref="setEditingInput"
    />

    <!-- 后缀插槽 -->
    <slot name="suffix" :node="item.node" :depth="item.depth"></slot>
  </div>
</template>

<style scoped>
/* 行级淡入动画，用于刷新/rehydrate 时减少突兀变化 */
.tv-anim { 
  animation: tv-fade-in 140ms ease; 
  will-change: opacity, transform; 
}

@keyframes tv-fade-in {
  from { 
    opacity: 0.01; 
    transform: translateY(2px); 
  }
  to { 
    opacity: 1; 
    transform: translateY(0); 
  }
}

@media (prefers-reduced-motion: reduce) {
  .tv-anim { 
    animation: none; 
  }
}
</style>